"use server";

import db from "@/server/connector/db";
import userPasswordService from "@/server/service/user-password-service";
import { Prisma, User } from "@prisma/client";
import { A1, A1_NAME } from "@/shared/agreements";
import agreementService from "@/server/service/agreement-service";
import { wrapAction } from "@/server/wrapper";
import AppError from "@/shared/app-error";
import { passwordStrength } from "@/shared/password";

async function createUser(username: string): Promise<User> {
  try {
    const user = await db.user.create({
      data: {
        username,
        createTime: new Date(),
        updateTime: new Date(),
      },
    });
    return user;
  } catch (err) {
    if (err instanceof Prisma.PrismaClientKnownRequestError) {
      switch (err.code) {
        case "P2002":
          throw new AppError({ code: "ERR_CANNOT_CREATE_USER", message: "用户名已存在" });
        default:
          throw new AppError({ code: "ERR_CANNOT_CREATE_USER", message: `未知错误:${err.code}` });
      }
    } else {
      throw new AppError({ code: "ERR_CANNOT_CREATE_USER", message: "未知错误" });
    }
  }
}

async function createUserPassword(user: User, password: string): Promise<void> {
  const encryptedPassword = await userPasswordService.encrypte(password);
  await db.userPassword.create({
    data: {
      userId: user.id,
      encryptedPassword,
      createTime: new Date(),
      updateTime: new Date(),
    },
  });
}

type RegisterParams = { username: string; password: string; agreements: string[] };

export async function register({ username, password, agreements }: RegisterParams) {
  return await wrapAction(async (): Promise<void> => {
    if (!agreements || !agreements.includes(A1)) {
      throw new AppError({ code: "ERR_NO_AGREEMENT", message: `请同意《${A1_NAME}》` });
    }

    const strength = passwordStrength(password);
    if (strength.score < 3) {
      const { feedback } = strength;
      const message = (feedback.warning || "密码强度太低。") + feedback.suggestions.join("");
      throw new AppError({ code: "ERR_WEEK_PASSWORD", message });
    }

    const user = await createUser(username);
    await agreementService.agree({ userId: user.id, agreement: A1 });
    await createUserPassword(user, password);
  });
}
